<template>
    <div ref="chartRef" class="chart-item"></div>
</template>

<script setup lang="ts">
import * as echarts from "echarts/core";
import { BarChart } from "echarts/charts";
import { TitleComponent, TooltipComponent, GridComponent, LegendComponent } from "echarts/components";
import { CanvasRenderer } from "echarts/renderers";
import { onMounted, onBeforeUnmount, watch, ref, nextTick } from "vue";

echarts.use([BarChart, TitleComponent, TooltipComponent, GridComponent, LegendComponent, CanvasRenderer]);

// -------------------- Props --------------------
export interface SeriesItem {
    name: string;
    data: number[];
    [key: string]: any;
}
interface Props {
    series: SeriesItem[];
    xAxisData?: string[];
    width?: string;
    height?: string;
    barWidth?: string | number;
    colors?: string[];
    legendSelectedMode?: boolean | "single" | "multiple";
    title?: string;
}
const props = withDefaults(defineProps<Props>(), {
    xAxisData: () => [],
    barWidth: "60%",
    colors: () => ["#5470c6", "#91cc75", "#fac858", "#ee6666", "#73c0de", "#3ba272", "#fc8452"],
    legendSelectedMode: false,
});

// -------------------- 内部变量 --------------------
const chartRef = ref<HTMLDivElement>();
let chartInst: echarts.ECharts | null = null;

// -------------------- 工具：计算百分比 --------------------
function calcPercentData(raw: number[][]) {
    const totalData: number[] = [];
    const colLen = raw[0]?.length ?? 0;
    for (let i = 0; i < colLen; i++) {
        let sum = 0;
        for (let j = 0; j < raw.length; j++) {
            sum += raw[j][i];
        }
        totalData.push(sum);
    }
    return raw.map(row => row.map((val, idx) => (totalData[idx] <= 0 ? 0 : val / totalData[idx])));
}

// -------------------- 生成 option --------------------
function buildOption() {
    const rawData = props.series.map(s => s.data);
    const percentData = calcPercentData(rawData);
    const series = props.series.map((s, sid) => ({
        name: s.name,
        type: "bar",
        stack: "total",
        barWidth: props.barWidth,
        label: {
            show: true,
            formatter: (params: { value: number }) => Math.round(params.value * 1000) / 10 + "%"
        },
        data: percentData[sid],
        itemStyle: {
            color: props.colors[sid % props.colors.length],
        },
    }));

    return {
        title: props.title ? { text: props.title, left: "center" } : { show: false },
        tooltip: {
            trigger: "axis",
            axisPointer: { type: "shadow" },
            formatter: (params: any[]) => {
                let res = params[0].axisValue + "<br/>";
                params.forEach(p => {
                    res += `${p.marker} ${p.seriesName}: ${Math.round(p.value * 1000) / 10}%<br/>`;
                });
                return res;
            },
        },
        legend: {
            selectedMode: props.legendSelectedMode,
            show: false,
        },
        grid: { left: "3%", right: "4%", bottom: "3%", containLabel: true },
        xAxis: { type: "category", data: props.xAxisData, axisLine: { lineStyle: { color: "#FFF" } } },
        yAxis: { type: "value", axisLabel: { formatter: "{value}%", lineStyle: { color: "#FFF" } } },
        series,
    };
}

// -------------------- 生命周期 --------------------
function render() {
    if (!chartRef.value) return;
    if (!chartInst) {
        chartInst = echarts.init(chartRef.value);
    }
    chartInst.setOption(buildOption(), true);
}

onMounted(() => {
    nextTick(render);
    chartRef.value && ro.observe(chartRef.value);
});
// 重新绘制echarts大小的方法
function resize() {
    chartInst?.resize();
}
// 监听容器大小
const ro = new ResizeObserver(() => resize());
onBeforeUnmount(() => {
    ro.disconnect();
    chartInst?.dispose();
});

// 监听数据变化
watch(
    () => props.series,
    () => nextTick(render),
    { deep: true }
);

// 监听窗口大小
const resizeHandler = () => chartInst?.resize();
window.addEventListener("resize", resizeHandler);
onBeforeUnmount(() => window.removeEventListener("resize", resizeHandler));

// -------------------- 暴露方法 --------------------
defineExpose({
    /** 手动调用 echarts 原生 setOption */
    setOption: (opt: any) => chartInst?.setOption(opt, true),
    /** 手动 resize */
    resize: () => chartInst?.resize(),
});
</script>
<style lang="scss" scoped>
.chart-item {
    width: 100%;
    height: 100%;
    ::v-deep(& > div, canvas) {
        height: 100%;
    }
}
</style>
